package org.bigjava.novelplatform.service.impl;

import cn.hutool.core.io.file.FileReader;
import cn.hutool.core.util.RandomUtil;
import lombok.extern.slf4j.Slf4j;
import org.bigjava.novelplatform.common.constant.ComplexConstant;
import org.bigjava.novelplatform.common.constant.NovelInfoConstant;
import org.bigjava.novelplatform.common.enums.ActionType;
import org.bigjava.novelplatform.common.enums.Subscribe;
import org.bigjava.novelplatform.common.enums.UserRole;
import org.bigjava.novelplatform.common.exception.UserActionException;
import org.bigjava.novelplatform.common.thirdparty.Mail;
import org.bigjava.novelplatform.common.utils.EncryptUtils;
import org.bigjava.novelplatform.common.utils.EntityTranslatorVo;
import org.bigjava.novelplatform.common.utils.EnvironmentUtils;
import org.bigjava.novelplatform.common.utils.StringUtils;
import org.bigjava.novelplatform.entity.*;
import org.bigjava.novelplatform.mapper.*;
import org.bigjava.novelplatform.service.UserService;
import org.bigjava.novelplatform.vo.*;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.io.File;
import java.time.Duration;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.function.Supplier;
import java.util.stream.Collectors;

import static org.bigjava.novelplatform.common.constant.NovelInfoConstant.*;
import static org.bigjava.novelplatform.common.exception.ExceptionCodeMessage.*;
import static org.bigjava.novelplatform.common.utils.AuthUtils.getAuthCode;

/**
 * @author ykh
 * @create 2022-04-04 8:48
 */
@Slf4j
@Service
public class UserServiceImpl implements UserService {

    @Resource
    private StringRedisTemplate stringRedisTemplate;

    @Resource
    private UsersMapper usersMapper;

    @Resource
    private BookRackMapper bookRackMapper;

    @Resource
    private CommentActionMapper commentActionMapper;

    @Resource
    private ChapterSaysMapper chapterSaysMapper;

    @Resource
    private BooksMapper booksMapper;

    @Resource
    private ChapterMapper chapterMapper;

    @Resource
    private WriterMapper writerMapper;

    @Resource
    private BrowsingMapper browsingMapper;


    /**
     * 注册
     * @param user
     * @return
     */
    @Override
    public UserInfoVo register(Users user) {
        //验证码校验
        Users dbUser = usersMapper.selectUserByEmail(user.getEmail());
        if (EnvironmentUtils.isProd()) {
            String authCode = dbUser.getAuthCode();
            String[] strings = authCode.split("_");
            if (!strings[1].equals(user.getAuthCode()) ||
                    !strings[0].equalsIgnoreCase(REGISTER_AUTH_CODE_PREFIX)) {
                throw new UserActionException(VERIFICATION_CODE_ERROR);
            }
        }else{
            if(dbUser == null){
                dbUser = new Users();
                dbUser.setEmail(user.getEmail());
                String randomStr = RandomUtil.randomString(6);
                user.setAuthCode(getAuthCode(randomStr, REGISTER_AUTH_CODE_PREFIX));
                usersMapper.insert(dbUser);
            }
        }
        //密码加密
        String randomString = RandomUtil.randomString(32);
        String password = EncryptUtils.salt(user.getPassword(), randomString);

        dbUser.setNickName(user.getNickName());
        dbUser.setSecretKey(randomString);
        dbUser.setPassword(password);

        usersMapper.updateById(dbUser);
        UserInfoVo userInfoVo = EntityTranslatorVo.toVo(dbUser,
                UserInfoVo.class,
                "id",
                "userType", "nickName", "headPortraitUrl");
        return userInfoVo;
    }

    @Override
    public UserInfoVo login(Users user) {
        Users dbUser = usersMapper.selectUserByEmail(user.getEmail());
        if (dbUser != null) {
            String password = EncryptUtils.salt(user.getPassword(), dbUser.getSecretKey());
            if(!EnvironmentUtils.isProd()){
                UserInfoVo userInfoVo = EntityTranslatorVo.toVo(dbUser,
                        UserInfoVo.class,
                        "id",
                        "userType", "nickName", "headPortraitUrl");
                return userInfoVo;
            }
            if (EnvironmentUtils.isProd() && password.equals(dbUser.getPassword())) {
                UserInfoVo userInfoVo = EntityTranslatorVo.toVo(dbUser,
                        UserInfoVo.class,
                        "id",
                        "userType", "nickName", "headPortraitUrl");
                return userInfoVo;
            }
        }
        throw new UserActionException(NOT_ERROR_MESSAGE);
    }

    @Override
    public List<BookRackItemVo> selectBookRackByUserId(Integer userId, String group) {
        List<BookRackItemVo> itemVos;
        //查询默认章节
        if (StringUtils.isEmpty(group)) {
            group = "";
        }
        List<String> strings = usersMapper.selectGroup(userId);
        if (strings.size() == 1) {
            itemVos = bookRackMapper.selectBookRackItemVo(userId, null);
        } else if (strings.size() == 0) {
            return null;
        } else {
            itemVos = bookRackMapper.selectBookRackItemVo(userId, group);
        }
        for (BookRackItemVo vo : itemVos) {
            Chapter chapter = chapterMapper.selectById(vo.getReadChapterId());
            if (chapter != null) {
                vo.setChapter(vo.getChapter() - chapter.getChapterOrder());
                vo.setReadChapterIdTitle(chapter.getTitle());
            } else {
                vo.setChapter(vo.getChapter());
                vo.setReadChapterIdTitle("还未阅读，立即阅读看看！！！");
            }
            vo.setWriterName(writerMapper.selectWriterNameById(vo.getWriterId()));
        }
        return itemVos;
    }


    @Override
    public void removeBookRack(Integer userId, List<Integer> bookIdList) {
        bookRackMapper.batchRemove(userId, bookIdList);
    }

    @Override
    public void topping(Integer userId, Integer bookId) {
        bookRackMapper.topping(userId, bookId, -1);
    }

    @Override
    public void bookSort(Integer userId, String group, List<Integer> bookIdList) {
        bookRackMapper.sort(userId, group, bookIdList);
    }

    @Override
    public String selectUserEmailById(Integer id) {
        return usersMapper.selectEmailById(id);
    }

    @Override
    public void becomeAnAuthor(Integer id) {
        //修改
        usersMapper.updateTypeById(id, UserRole.WRITER);
        Writer writer = new Writer();
        writer.setUserId(id);
        writer.setRegisterWriterTime(new Date());
        writerMapper.insert(writer);

    }

    @Override
    public boolean UpdateSubscribeState(Integer userId, Integer bookId) {
        //查询当前订阅状态
        Integer subscribe = bookRackMapper.selectSubscribeByBookId(bookId);
        if (Subscribe.NOT_SIGNING.getCode().equals(subscribe)) {
            bookRackMapper.updateSubscribe(userId, bookId, Subscribe.SIGNING);
            return true;
        } else {
            bookRackMapper.updateSubscribe(userId, bookId, Subscribe.NOT_SIGNING);
            return false;
        }
        //修改订阅状态
//
    }

    @Transactional(rollbackFor = RuntimeException.class)
    @Override
    public ChapterSays giveTheThumbsUp(Integer userId, Long id, String actionType, ActionType oldType) {
        ActionType type = null;
        if (actionType.equalsIgnoreCase(ActionType.LIKE.toString())) {
            type = ActionType.LIKE;
        } else if (actionType.equalsIgnoreCase(ActionType.DOWNHOLE.toString())) {
            type = ActionType.DOWNHOLE;
        } else if (actionType.equalsIgnoreCase(ActionType.CANCEL.toString())) {
            type = ActionType.CANCEL;
        } else {
            throw new UserActionException(UNRECOGNIZED_TYPE);
        }
        //comment_action 评论操作记录
        //查询用户对id的记录是否存在
        CommentAction commentAction = commentActionMapper.selectByUserIdAndCommentId(userId, id);
        if (commentAction == null) {
            //添加记录
            commentActionMapper.addRecord(userId, id, type);
            //增加点赞数
            chapterSaysMapper.addRecord(id, type);
        } else if (oldType.name().equals("CANCEL")) {
            commentActionMapper.updateRecord(userId, id, type);
            //增加点赞数
            chapterSaysMapper.addRecord(id, type);
        } else {
            //修改记录为取消，减少本章说动作
            commentActionMapper.updateRecord(userId, id, ActionType.CANCEL);
            if (oldType == null) {
                throw new UserActionException(NON_COMPLIANT_PARAMETERS);
            } else if (oldType.name().equals("LIKE")) {

                ActionType types = ActionType.LIKE;
                chapterSaysMapper.reduceRecord(id, types);
            } else if (oldType.name().equals("DOWNHOLE")) {
                ActionType types = ActionType.DOWNHOLE;
                chapterSaysMapper.reduceRecord(id, types);
            }

        }
        return chapterSaysMapper.selectById(id);
    }


    @Override
    public void updateUserInfoById(Integer id, String path, String nickName, String email, String code) {
        if (!StringUtils.isEmpty(code)) {
            String s = stringRedisTemplate.opsForValue().get(keyConstructor(email, id));
            if (s != null && s.equals(code)) {
                usersMapper.updateUserInfoById(id, path, nickName, email);
            } else {
                throw new UserActionException(VERIFICATION_CODE_ERROR);
            }
        } else {
            usersMapper.updateUserInfoById(id, path, nickName, null);
        }


    }


    @Override
    public void moveBookRack(Integer userId, String oldGroup, String targetGroup, List<Integer> bookIdList) {
        bookRackMapper.moveBookRack(userId, oldGroup, targetGroup, bookIdList);
    }

    @Override
    public void addBookRack(Integer userId, String group, List<Integer> bookIdList) {
        //TODO:应该防止书架书籍重复
        booksMapper.addSubscriptionBatch(bookIdList);
        //插入书架
        bookRackMapper.batchInsert(userId, group, bookIdList);
    }

    @Override
    public boolean updateBookRack(Integer userId, String group, Integer bookId) {
        //确认当前书籍不在书架,如果书籍已经被逻辑删除，也视为不存在
        if (bookRackMapper.selectBookRackByUserIdAndBookId(userId, bookId) == null) {
            //加入书架
            BookRack bookRack = new BookRack();
            bookRack.setBookId(bookId);
            bookRack.setUserId(userId);
            bookRack.setJoinTime(new Date());
            bookRack.setContribution(0L);
            if (StringUtils.isEmpty(group)) {
                bookRack.setGroupName(DEFAULT_GROUP);
            } else {
                bookRack.setGroupName(group);
            }
            //收藏数加1
            booksMapper.addSubscription(bookId);
            bookRackMapper.insert(bookRack);
            return true;
        } else {
            log.warn("书籍{}已存在用户{}的书架中", bookId, userId);
            return false;
        }
    }

    @Override
    public Users resetPasswords(Integer userId, String newPassword, String inputAuthCode) {
        //查询数据库中的用户
        Users users = usersMapper.selectById(userId);
        //验证码校验
        String authCode = users.getAuthCode();
        String[] strings = authCode.split(SEPARATOR.toString());
        if (!strings[1].equals(inputAuthCode) ||
                !strings[0].equalsIgnoreCase(RESET_PASSWORDS_AUTH_CODE_PREFIX)) {
            //验证码无效
            throw new UserActionException(USER_REST_PASSWORD);
        } else {
            //设置新密码
            //加密
            String randomString = RandomUtil.randomString(32);
            String password = EncryptUtils.salt(newPassword, randomString);
            users.setPassword(password);
            users.setSecretKey(randomString);
            usersMapper.updatePasswordByEmail(users.getEmail(), password);
        }
        return users;
    }


    @Resource
    private Mail mail;

    @Value("${novel.web.resourcePath:}")
    private String resourcePath;


    @Transactional(rollbackFor = {RuntimeException.class})
    @Override
    public boolean sendMailVerification(String email, Supplier<String> getRandomString, String readFileName) {
        //生成字符串
        String randomString = getRandomString.get();

        //读取Email.html文件
        if (StringUtils.isEmpty(resourcePath)) {
            resourcePath = ComplexConstant.RESOURCE_PATH;
        }
        resourcePath += readFileName;
        String readString = null;
        File htmlFile = new File(resourcePath);
        if (htmlFile.exists()) {

            FileReader fileReader = FileReader.create(htmlFile);
            readString = fileReader.readString();

        } else {
            log.warn("不存在的文件{}", resourcePath);
        }
        //发送邮箱
        if (StringUtils.isEmpty(readString)) {
            mail.sendMail(email, "验证邮箱", randomString);
        } else {
            //将字符串的第一个<span class="randomString"><span/>替换
            readString = readString.replace("<span class=\"randomString\">[\\s\\S]*<span/>",
                    "<span class=\"randomString\">" +
                            randomString + "<span/>");
            mail.sendMailPlus(email, "验证邮箱", readString);
        }
        return true;

    }

    @Transactional(rollbackFor = {RuntimeException.class})
    @Override
    public boolean sendMailResetPasswords(Integer id) {
        Users users = usersMapper.selectById(id);
        if (Objects.isNull(users)) {
            //不存在的用户绝对不能发送改请求
            throw new RuntimeException("不存在的用户");
        }
        String email = users.getEmail();
        if (isOk(users, NovelInfoConstant.RESET_PASSWORDS_AUTH_CODE_PREFIX)) {
            return sendMailVerification(email,
                    () -> {
                        String randomStr = RandomUtil.randomString(6);
                        //保存验证码
                        Users user = new Users();
                        //
                        user.setAuthCode(getAuthCode(randomStr, RESET_PASSWORDS_AUTH_CODE_PREFIX));
                        user.setId(user.getId());
                        usersMapper.updateById(user);
                        return randomStr;
                    }
                    , RESET_PASSWORDS_VIM);
        }
        return false;
    }

    @Transactional(rollbackFor = {RuntimeException.class})
    @Override
    public boolean sendMailRegister(String email) {
        //邮箱是否存在
        Users mailBox = usersMapper.selectUserByEmail(email);
        //不存在
        if (Objects.isNull(mailBox)) {
            //保存邮箱
            mailBox = new Users();
            mailBox.setEmail(email);
            usersMapper.insert(mailBox);
        }
        Users user = mailBox;
        if (isOk(mailBox, REGISTER_AUTH_CODE_PREFIX)) {
            return sendMailVerification(email,
                    () -> {
                        String randomStr = RandomUtil.randomString(6);
                        //保存验证码
                        user.setAuthCode(getAuthCode(randomStr, REGISTER_AUTH_CODE_PREFIX));
                        usersMapper.updateById(user);
                        return randomStr;
                    }
                    , REGISTER_VIM);
        }
        return false;
    }




    /**
     * 判断用户是否可以继续操作
     *
     * @param users
     * @param tage
     * @return
     */
    public boolean isOk(Users users, String tage) {
        String authCode = users.getAuthCode();

        if (!StringUtils.isEmpty(authCode)) {
            String[] strings = authCode.split(SEPARATOR.toString());
            String timeStr = strings[2];
            Long time = Long.valueOf(timeStr);
            //小于最小等待时间
            if ((System.currentTimeMillis() - time) < NovelInfoConstant.MIN_WAIT_TIME) {
                throw new UserActionException(ACTION_FREQUENTLY);
//                return false;
            }
            //需要注册
            if (REGISTER_AUTH_CODE_PREFIX.equals(tage)) {
                //上次存入的验证码为修改密码
                if (NovelInfoConstant.RESET_PASSWORDS_AUTH_CODE_PREFIX.equals(strings[0])) {
                    throw new UserActionException(USED_EMAIL);
//                    return false;
                    //上次注册成功
                } else if (!StringUtils.isEmpty(users.getPassword())) {
//                    return false;
                    throw new UserActionException(USED_EMAIL);
                }
            }
        }
        return true;
    }


    /**
     * 查询用户的页面
     *
     * @param id
     */
    @Override
    public UserInquireVo userInquire(Integer id) {
        UserInquireVo userInquireVo = usersMapper.userInquire(id);

        int i = usersMapper.userInquireboook(id);
        userInquireVo.setBook(i);


        return userInquireVo;
    }

    @Override
    public SimpleBookRackVo selectBookRackByUserIdAndBookId(Integer bookId, Integer id) {
        BookRack bookRack = bookRackMapper.selectBookRackByUserIdAndBookId(bookId, id);
        SimpleBookRackVo simpleBookRackVo = new SimpleBookRackVo();
        if (bookRack == null) {
            return simpleBookRackVo;
        }
        BeanUtils.copyProperties(bookRack, simpleBookRackVo);
        Books books = booksMapper.selectById(bookId);
        simpleBookRackVo.setBookName(books.getBookName());
        Long lastPositionId = bookRack.getLastPositionId();
        if (lastPositionId != null) {
            Chapter lastChapter = chapterMapper.selectById(lastPositionId);
            simpleBookRackVo.setLastPositionTitle(lastChapter.getTitle());
        }
        Long readChapterId = bookRack.getReadChapterId();
        if (readChapterId != null) {
            Chapter readChapter = chapterMapper.selectById(readChapterId);
            simpleBookRackVo.setReadChapterTitle(readChapter.getTitle());
        }
        return simpleBookRackVo;
    }

    @Override
    public List<String> selectGroup(Integer userId) {
        List<String> grouts = usersMapper.selectGroup(userId);
        return grouts;
    }


    @Override
    public void replaceMailbox(String email, Integer userId) {
        if (usersMapper.selectEmail(email) == null) {
            String key = keyConstructor(email, userId);
            sendMailVerification(email,
                    () -> {
                        String randomStr = RandomUtil.randomString(6);
                        //保存验证码
                        stringRedisTemplate.opsForValue().set(key, randomStr, Duration.ofMinutes(5L));
                        return randomStr;
                    }
                    , REGISTER_VIM);
        } else {
            throw new UserActionException(USED_EMAIL);
        }
    }

    @Override
    public void logicalDeletion(Integer id, List<Integer> bookIdList) {
        bookRackMapper.logicalDeletion(id, bookIdList);
    }


    /**
     * 构造key
     *
     * @param email
     * @param userId
     * @return
     */
    public String keyConstructor(String email, Integer userId) {
        return email + userId;
    }


    /**
     * 保存本章说评论
     *
     * @param chapterSays
     */
    @Override
    public ChapterSays insterChaterSays(ChapterSays chapterSays) {
        chapterSaysMapper.insert(chapterSays);
        return chapterSays;
    }

    /***
     * 保存浏览记录
     * @param browsing
     */
    @Override
    public void Savethebrowse(Browsing browsing, Integer bookId) {
//        根据传来的章节id和用户的id查看是否存在用户的浏览记录
        List<Browsing> browsingsss = browsingMapper.selectUserid(browsing.getUserId());
        if (browsingsss == null || browsingsss.size() == 0) {
            browsingMapper.insert(browsing);
        } else {
            for (Browsing c : browsingsss) {
                Long browsingId = c.getBrowsingId().longValue();
                Chapter chapter = chapterMapper.selectChapter(browsingId);


                //  比较我传来的书籍id  如果相同就修改浏览保存表的章节id
                if (chapter.getBookId().equals(bookId)) {
                    // 如果存在浏览记录还要区别是否为同一本书 如果为同一本书就修改字段 ，如果不是就添加
                    browsingMapper.updateBrowsingId(c.getId(), browsing.getBrowsingId());
                    break;
                } else {
                    browsingMapper.insert(browsing);
                }
            }
        }
        BookRack bookRack = bookRackMapper.selectBookRackByUserIdAndBookId(bookId, browsing.getUserId());
        if (bookRack != null) {
            bookRack.setLastPositionId(browsing.getBrowsingId());
            bookRack.setReadChapterId(browsing.getBrowsingId());
            bookRack.setLastReadTime(new Date());
            bookRackMapper.updateById(bookRack);

        }
    }

    /**
     * 根据用户的id和书籍的id进行查询章节的id从而得到章节顺序
     *
     * @param bookId
     * @param id
     */
    @Override
    public Integer selectChapters(Integer bookId, Integer id) {
        List<Browsing> browsings = browsingMapper.selectUserid(id);

        Integer a = 1;
        for (Browsing c : browsings) {
            Long browsingId = c.getBrowsingId().longValue();
            Chapter chapter = chapterMapper.selectChapter(browsingId);

            if (chapter.getBookId().equals(bookId)) {
                Integer chapterOrder = chapter.getChapterOrder();
                a = chapterOrder;
                break;
            }
        }

        return a;

    }


}



